package display;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JPanel;

import net.sf.epsgraphics.EpsGraphics;

import algorithm.Algorithm;

public class SquareDisplay extends JPanel implements Display, Runnable {
	
	JPanel parent = null;
	Algorithm rule;

	Thread thCycle;
	int w, h, w2, h2, delay = 1000, it, gens, n = 11, nvert;
	Image buffImage;
	Graphics buffGraphics;
	byte L[]; 
	byte l[][];
	
	boolean bCycle = false, bSet = false;
	
	private List<DisplayListener> listeners = new ArrayList<DisplayListener>();

	/**
	 * 
	 * @param meret - size of matrix
	 * @param rule - the rule
	 * @param delay - delay between the generation changes in milliseconds
	 * @param generations - number of generations
	 * @param bshow
	 * @param parent
	 */
	public SquareDisplay(int meret, Algorithm rule, int delay, int generations, boolean bshow, JPanel parent) {
		// TODO Auto-generated constructor stub
		this.parent = parent;
		n = meret;
		this.delay = delay;
		gens = generations;
		bSet = bshow;
		this.rule = rule;
		l = new byte[n][n];
		it = 0; // number of iterations performed
		setBackground(Color.WHITE);
		setVisible(true);
	}
	

	@Override
	public void run() {
		// TODO Auto-generated method stub
		while (it < gens) {
			if (Thread.currentThread() != thCycle)
				return;
			try {
				Thread.sleep(delay);
			} catch (InterruptedException e) {
			}
			cycle();
			repaint();
		}
		stopSimulation();

	}

	@Override
	public void startSimulation() {
		// TODO Auto-generated method stub
		thCycle = new Thread(this);
		thCycle.start();

	}

	@Override
	public void stopSimulation() {
		// TODO Auto-generated method stub
		for (DisplayListener hl : listeners)
            hl.simulationStopped();
		thCycle = null;
	}

	@Override
	public boolean isReady() {
		// TODO Auto-generated method stub
		return it >= gens;
	}

	@Override
	public void addListener(DisplayListener toAdd) {
		listeners.add(toAdd);
	}

	@Override
	public void abort() {
		// TODO Auto-generated method stub
		it = gens + 1;
		stopSimulation();
	}

	@Override
	public boolean saveScreenShot(File f) {
		// TODO Auto-generated method stub
		boolean success = true;

		FileOutputStream outputStream = null;
		EpsGraphics eps = null;
		try {
			outputStream = new FileOutputStream(f);
			Dimension d = getSize();
			eps = new EpsGraphics("Diagram", outputStream, 0, 0, d.width,
					d.height, net.sf.epsgraphics.ColorMode.COLOR_RGB);
			paint(eps);
		} catch (Exception ex) {
			ex.printStackTrace();
			success = false;
		} finally {
			try {
				eps.flush();
				eps.close();
			} catch (Exception ex) {
				ex.printStackTrace();
				success = false;
			}

		}

		return success;
	}

	@Override
	public void setupSize() {
		// TODO Auto-generated method stub
		w = parent.getSize().width;
		h = parent.getSize().height;
		setSize(w, h);
		buffImage = createImage(w, h);
		buffGraphics = buffImage.getGraphics();
		setBackground(Color.white);
		
	}

	@Override
	public void destroy() {
		// TODO Auto-generated method stub
		
	}

	/**
	 * Initializing the matrix 
	 */
	@Override
	public void init() {
		// TODO Auto-generated method stub
		
		for (int i = 1; i < n; i++)
			for (int j = 1; j < n; j++)
				l[i][j] = 0;
		
		nvert = n * n;		
		
		L = rule.init();

		it = 0;
		
		setupSize();
		
		for (DisplayListener hl : listeners) {
            hl.setIterationCount(it);
            hl.setPopulationCount(rule.getC(), rule.getD());
		}
		
		repaint();
	}
	
	void cycle() {
		it++;
		rule.cycle(L);
		repaint();
		for (DisplayListener hl : listeners) {
            hl.setIterationCount(it);
            hl.setPopulationCount(rule.getC(), rule.getD());
		}
	}
	
	public void paintComponent(Graphics g) {
		super.paintComponent(g);		
		buffGraphics.setColor(Color.white);
		buffGraphics.fillRect(0, 0,parent.getSize().width, parent.getSize().height);
		
		int p = 0;
		for (int i = 0; i < n; i++)
			for (int j = 0; j < n; j++)
				l[i][j] = L[p++];
		
		
		for(int i = 0; i < n; i++) {
			for(int j = 0; j < n; j++) {
				if ( l[i][j] == 1)
					buffGraphics.setColor(Color.RED);
				else
					buffGraphics.setColor(Color.BLUE);
				buffGraphics.fillRect(getWidth()/2-n/2+i,getHeight()/2-n/2+j,1,1);
			}
		}
		g.drawImage(buffImage, 0, 0, this);
	}
	
	public void update(Graphics g) {
		paint(g);
	}

}
